package fr.imag.adele.cprobes.impl;

import java.util.Dictionary;
import java.util.Hashtable;

import org.osgi.framework.BundleContext;
import org.osgi.service.event.Event;
import org.osgi.service.event.EventAdmin;
import org.osgi.service.event.EventConstants;
import org.osgi.service.event.EventHandler;
import org.osgi.util.tracker.ServiceTracker;

import fr.imag.adele.cprobes.abstracts.AbstractProbe;
import fr.imag.adele.cprobes.services.DataCollector;
import fr.imag.adele.cprobes.services.DataSender;
import fr.imag.adele.cprobes.services.Scheduler;
import fr.imag.adele.cprobes.util.DataEvent;
import fr.imag.adele.cprobes.util.DataSet;

/**
 * The Composite Probe implementation of the Probe.
 * It sends the received events to the composite probes (internal probes) 
 * and receive the processed events from those internal probes to be sent to 
 * interested external probes (and/or clients).
 * 
 * @author Bassem DEBBABI
 *
 */
public class CompositeProbe extends AbstractProbe implements EventHandler {
	private ServiceTracker 	m_tracker;	
	private BundleContext 	m_bundleContext;			
	private EventAdmin 		ea;
	
	/**
	 * Constructor
	 * Used to retrieve the BundleContext
	 * @param bc BundleContext
	 */
	public CompositeProbe(BundleContext bc) {
		m_bundleContext = bc;
	}
	/**
	 * Called when the instance started.
	 */
	public void starting() {
		super.starting();		
		m_tracker = new ServiceTracker(m_bundleContext, EventAdmin.class.getName(), null);
		
		String[] resources = getDataSender().getProvidedResources();
		///// listening to intern events
		Dictionary dico = new Hashtable();				
		for (int i=0; i<resources.length;i++){
			resources[i] = getProbeId() + "/out/" + resources[i]; 
		}
		dico.put(EventConstants.EVENT_TOPIC, resources);	
		m_bundleContext.registerService(EventHandler.class.getName(), this, dico);		
		//////
		m_tracker.open();
	}
	/**
	 * Called when the instance stopped.
	 */
	public void stoping() {
		super.stoping();
		m_tracker.close();
	}
	
	/**
	 * Process the collected data.
	 * In this class implementation (CompositeProbe), the collected data is
	 * forwarded to internal probes to be processed.
	 * 
	 */	
	public void process() {
		// get the collected data
		DataSet dataSet = getCollectedData();
		// send events about these data to internatl probes
		// == event.source = this.probeid + / + oldevent.source
		EventAdmin ea = (EventAdmin)m_tracker.getService();
		if (ea != null) {
			if (dataSet != null) {
				for (int i=0; i<dataSet.size(); i++){
					DataEvent dataEvent = dataSet.getDataEvent(i);
					dataEvent.setSource(getProbeId() + "/in/" + dataEvent.getSource());
					ea.sendEvent(new Event(dataEvent.getSource() + "/" + dataEvent.getResource(), dataEvent.getAllData()));				
				}
			}						
		}		
	}
	/**
	 * receive internal event and send it to the DataSender
	 */ 
	public void handleEvent(Event event) {
		DataEvent dataEvent = new DataEvent(event.getProperty(DataEvent.CP_EVENT_RESOURCE).toString(),
				event.getProperty(DataEvent.CP_EVENT_SOURCE).toString(),
				event.getProperty(DataEvent.CP_EVENT_TIMESTAMP).toString(),
				event.getProperty(DataEvent.CP_EVENT_VALUE),
				event.getProperty(DataEvent.CP_EVENT_UNIT).toString(),null);
		DataSet dataSet = new DataSet();
		dataSet.add(dataEvent);
		sendProcessedData(dataSet);
	}	
	
	//// Binding methods
	// TODO if we can bind directly with methods from the parent class
	// then we have to move these methods to the parent class.
	
	public void bindScheduler(Scheduler scheduler) {			
		setScheduler(scheduler);
	}
	public void unbindScheduler() {
		setScheduler(null);
	}
	public void bindDataCollector(DataCollector dataCollector) {
		setDataCollector(dataCollector);
	}
	public void unbindDataCollector() {
		setDataCollector(null);
	}
	public void bindDataSender(DataSender dataSender) {
		setDataSender(dataSender);
	}
	public void unbindDataSender() {
		setDataSender(null);
	}
	
	////
		
}
